#include "./sensor.h"
#include "../rtos/mutex.h"
#include "../xlib/gpio.h"
#include "../pub_driver/i2c.h"
#include "../rtx/rtx_os.h"
#include "../pub_driver/trmap.h"

namespace ice_driver {

Sensor sensor;

namespace sensor_impl {

using namespace stm32f1::gpio;
using namespace stm32f1;
	
using SDA = PB<7>;
using SCL = PB<8>;
using RDY = PB<6>;

uint16_t lastTim2Cnt = 0;
uint16_t stirSpeed = 0; 

using ICE_FULL = PB<3>;
using STIR_SPEED = PA<1>; // TIM2_CH2
using LEAK = PC<3>;
using BUCKET_HIGH = PC<4>;
using BUCKET_LOW = PC<5>;

static constexpr uint8_t ADDR = 0x48;
using ADS1115 = pub_driver::I2cInterface<ADDR, SCL, SDA>;

static constexpr uint8_t CONVERSION_REG = 0;
static constexpr uint8_t CONFIG_REG = 1;

static constexpr uint16_t CH1_CFG = 0x8483;
static constexpr uint16_t CH2_CFG = 0xB483;

const uint32_t TR_COUNT = sizeof (TRMap) / sizeof (TRMap[0]);
const uint32_t R_MIN = TRMap[TR_COUNT - 1];
const uint32_t R_MAX = TRMap[0];
constexpr uint32_t NOT_FOUND_INDEX = static_cast<uint32_t>(-1);

}

using namespace sensor_impl;

void Sensor::init() {

    rcc::enable<SCL, SDA, RDY, ICE_FULL, STIR_SPEED, LEAK, BUCKET_HIGH, BUCKET_LOW>();
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN;
    config<
        Cfg<SCL, Mode::OUT_50MHz_OD>,
        Cfg<SDA, Mode::OUT_50MHz_OD>,
        Cfg<RDY, Mode::INPUT_FLOAT>,
        Cfg<ICE_FULL, Mode::INPUT_FLOAT>,
        Cfg<STIR_SPEED, Mode::INPUT_FLOAT>,
        Cfg<LEAK, Mode::INPUT_FLOAT>,
        Cfg<BUCKET_HIGH, Mode::INPUT_FLOAT>,
        Cfg<BUCKET_LOW, Mode::INPUT_FLOAT>
    >();

    ADS1115::stop();

    TIM2->CR1 = 0x00;
    TIM2->CR2 = 0x00;
    TIM2->SMCR = 0x67;
    TIM2->CCER = 0x0000;
    TIM2->CCMR1 = 0x0100;
    TIM2->CR1 = 0x01;

    // TIM3 每隔500ms测量 速度
    TIM3->CR1 = 0x00;
    TIM3->CR2 = 0x00;
    TIM3->PSC = 720 - 1;
    TIM3->ARR = 1000 * 50 - 1;
    TIM3->EGR = 0x01;
    TIM3->DIER = 0x01;
    TIM3->CR1 = 0x01;
    NVIC_EnableIRQ(TIM3_IRQn);
}

static uint32_t find(uint32_t val) {
    if ((val > R_MAX) || (val < R_MIN)) {
        return NOT_FOUND_INDEX;
    }
    uint32_t left = 0;
    uint32_t right = TR_COUNT - 1;

    while ((right - left) > 1) {
        uint32_t index = (left + right) / 2;
        uint32_t cv = TRMap[index];
        if (val > cv) {
            right = index;
        } else if (val < cv) {
            left = index;
        } else {
            return index;
        }
    }
    return left;
}

static bool read(uint16_t cfg, uint32_t &val) {
    uint16_t v;
    bool r = ADS1115::write(CONFIG_REG, cfg);
    if (!r) {
        return false;
    }

    r = ADS1115::read(CONVERSION_REG, v);
    if (!r) {
        return false;
    }

    uint32_t tmp = v * 2048 / 32768;
    val = 20000 * tmp / (1800 - tmp);

    return true;
}

static bool read_find(uint16_t cfg, int8_t &val) {
    uint32_t tmp;
    bool ret = read(cfg, tmp);
    if (!ret) {
        return false;
    }
    uint32_t index = find(tmp);
    if (index == NOT_FOUND_INDEX) {
        return false;
    }
    val = static_cast<int8_t>(index) - 40;

    return true;
}

void Sensor::read_temp() {
    m_env_ok = read_find(CH1_CFG, m_env_temp);
    
    m_evap_ok = read_find(CH2_CFG, m_evap_temp);
}

uint16_t Sensor::stir_speed() {
    return stirSpeed;
}

bool Sensor::is_ice_full() {
    return !ICE_FULL::read();
}

bool Sensor::is_bucket_high() {
    return BUCKET_HIGH::read();
}

bool Sensor::is_bucket_low() {
    return !BUCKET_LOW::read();
}

bool Sensor::is_leak() {
    return LEAK::read();
}

}

using namespace ice_driver;

extern "C"
void TIM3_IRQHandler() {
    if (TIM3->SR & TIM_SR_UIF) {
        TIM3->SR &= ~TIM_SR_UIF;
    }
    uint16_t cnt = TIM2->CNT;
    if (cnt < lastTim2Cnt) {
		stirSpeed = (cnt + 0xFFFF - lastTim2Cnt) * 2;
    } else {
        stirSpeed = (cnt - lastTim2Cnt) * 2;
    }
    lastTim2Cnt = cnt;
}






